/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.workflow.inventory.extension;

import com.bifrost.constant.OrderType;
import com.bifrost.entity.*;
import com.bifrost.exception.InventoryUnavailableException;
import com.bifrost.extension.ExtensionResultHolder;
import com.bifrost.extension.ExtensionResultStatusType;
import com.bifrost.repository.PromotionConstraintRepository;
import com.bifrost.service.InventoryService;
import com.bifrost.service.ProductSkuService;
import com.bifrost.service.PromotionService;
import com.bifrost.util.DateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 *
 *
 *@author joewee
 *@version 1.0.0
 *@Date 2018/3/18 00:35
 */
@Component
public class PromotionInventoryServiceExtensionHandler extends AbstractInventoryServiceExtensionHandler {
private Logger logger = LoggerFactory.getLogger(PromotionInventoryServiceExtensionHandler.class);
    @Autowired
    ProductSkuService productSkuService;
    @Autowired
    protected InventoryServiceExtensionManager extensionManager;
    @Autowired
    PromotionService promotionService;
    @Autowired
    PromotionConstraintRepository promotionConstraintRepository;

    @PostConstruct
    public void init(){
        if (isEnabled()) {
            if(logger.isDebugEnabled()){
                logger.debug("register promotionInventoryServiceExtensionHandler in  InventoryServiceExtensionManager");
            }
            extensionManager.registerHandler(this);
        }
    }
    /**
     * 检索可用库存
     * @param skus
     * @param context
     * @param result
     * @return
     */
    @Override
    public ExtensionResultStatusType retrieveQuantitiesAvailable(Collection<ProductSku> skus, Map<String, Object> context, ExtensionResultHolder<Map<ProductSku, Integer>> result) {
       if(context == null){
           return ExtensionResultStatusType.NOT_HANDLED;
       }
        String type =context.getOrDefault(InventoryService.ORDER_TYPE, OrderType.GENERAL).toString();
        if(!OrderType.GROUPON.equalsIgnoreCase(type) && !OrderType.SECKILL.equalsIgnoreCase(type)){
            return ExtensionResultStatusType.NOT_HANDLED;
        }else{
            return ExtensionResultStatusType.HANDLED_STOP;
        }
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ExtensionResultStatusType decrementInventory(Map<ProductSku, Integer> skuQuantities, Map<String, Object> context) throws InventoryUnavailableException {
        if(context == null){
            return ExtensionResultStatusType.NOT_HANDLED;
        }
        String type =context.getOrDefault(InventoryService.ORDER_TYPE, OrderType.GENERAL).toString();
        if(!OrderType.GROUPON.equalsIgnoreCase(type) && !OrderType.SECKILL.equalsIgnoreCase(type)){
            return ExtensionResultStatusType.NOT_HANDLED;
        }else{
            Order order = (Order) context.get(InventoryService.ORDER_KEY);
            Customer customer = order.getCustomer();
            List<OrderItem> orderItemList = order.getOrderItems();
            if(CollectionUtils.isNotEmpty(orderItemList)){
                OrderItem item = orderItemList.get(0);
                Long appliedPromotionId = item.getAppliedPromoId();
                if(appliedPromotionId == null){
                    throw new RuntimeException("appliedPromotionId is null");
                }
                Promotion promotion = promotionService.find(appliedPromotionId);
                if(promotion == null){
                    throw new RuntimeException("promotion is null");
                }
                if(!DateUtils.isActive(promotion.getStartTime(), promotion.getEndTime())){
                    throw new RuntimeException("promotion is invalid");
                }
                for (Map.Entry<ProductSku, Integer> entry : skuQuantities.entrySet()) {
                    ProductSku sku = entry.getKey();
                    Product product = sku.getProduct();
                    Integer quantity = entry.getValue();
                    if (quantity == null || quantity < 1) {
                        throw new IllegalArgumentException("quantity: " + quantity + "is invalid");
                    }
                    PromotionSku promotionSku = promotionService.findByPromotionAndSku(promotion, sku);
                    Integer inventoryAvailable = promotionSku.getInventoryAvailable();
                    if(inventoryAvailable == null || inventoryAvailable < 1){
                        logger.error("inventoryAvailable has error for promotionSkuId:"+ promotionSku.getId());
                        throw new InventoryUnavailableException("inventoryAvailable: " + inventoryAvailable + "is invalid");
                    }
                    if(inventoryAvailable < quantity){
                        throw new InventoryUnavailableException("库存不足.", sku.getSkuId(), quantity, inventoryAvailable);
                    }
                    int row = promotionService.decrementInventory(promotionSku, quantity);
                    if(row != 1) {
                        throw new RuntimeException("decrementInventory failed");
                    }
                    //促销订单数量控制
                    if(Boolean.TRUE.equals(promotionSku.getHasLimit())) {
                        Integer limitQuantity = promotionSku.getLimitQuantity();
                        if(null == limitQuantity || limitQuantity < 1) {
                            throw new RuntimeException("促销信息配置错误");
                        }
                        PromotionConstraint dbpc =
                                promotionConstraintRepository.findByCustomerAndPromotionAndProductId(customer, promotion, product.getProductId());
                        if (null != dbpc) {
                            Integer quantityFresh = dbpc.getQuantity() + quantity;
                            if (quantityFresh > limitQuantity) {
                                throw new RuntimeException("数量超过购买限制");
                            }
                            dbpc.setQuantity(quantityFresh);
                        }else {
                            PromotionConstraint pc = new PromotionConstraint();
                            pc.setCustomer(order.getCustomer());
                            pc.setQuantity(quantity);
                            pc.setPromotion(promotion);
                            pc.setProductId(product.getProductId());
                            try {
                                promotionConstraintRepository.save(pc);
                            }catch (Exception e){
                                logger.error(e.getMessage(),e);
                                throw new RuntimeException("数量超过购买限制");
                            }
                        }
                    }
                }
            }
            return ExtensionResultStatusType.HANDLED_STOP;
        }
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ExtensionResultStatusType incrementInventory(Map<ProductSku, Integer> skuQuantities, Map<String, Object> context) {
        if (context == null) {
            return ExtensionResultStatusType.NOT_HANDLED;
        }
        String type = context.getOrDefault(InventoryService.ORDER_TYPE, OrderType.GENERAL).toString();
        if (!OrderType.GROUPON.equalsIgnoreCase(type) && !OrderType.SECKILL.equalsIgnoreCase(type)) {
            return ExtensionResultStatusType.NOT_HANDLED;
        } else {
            //TODO 促销订单的售后服务单退货
            Order order = (Order) context.get(InventoryService.ORDER_KEY);
            Customer customer = order.getCustomer();
            List<OrderItem> orderItemList = order.getOrderItems();
            if (CollectionUtils.isNotEmpty(orderItemList)) {
                OrderItem item = orderItemList.get(0);
                Long appliedPromotionId = item.getAppliedPromoId();
                Promotion promotion = promotionService.find(appliedPromotionId);
                if (promotion == null) {
                    throw new RuntimeException("promotion is null");
                }
                for (Map.Entry<ProductSku, Integer> entry : skuQuantities.entrySet()) {
                    ProductSku sku = entry.getKey();
                    Integer quantity = entry.getValue();
                    if (quantity == null || quantity < 1) {
                        throw new IllegalArgumentException("quantity: " + quantity + "is invalid");
                    }
                    PromotionSku promotionSku = promotionService.findByPromotionAndSku(promotion, sku);
                    Integer inventoryAvailable = promotionSku.getInventoryAvailable();
                    if (inventoryAvailable == null || inventoryAvailable < 0) {
                        logger.error("inventoryAvailable has error for promotionSkuId:" + promotionSku.getId());
                        throw new IllegalArgumentException("inventoryAvailable: " + inventoryAvailable + "is invalid");
                    }
                    if (promotionSku.getInventory() < quantity + inventoryAvailable) {
                        throw new IllegalArgumentException("quantity:" + quantity + "is invalid");
                    }
                    int row = promotionService.incrementInventory(promotionSku, quantity);
                    if (row != 1) {
                        throw new RuntimeException("incrementInventory failed");
                    }
                    //促销订单数量控制
                    if (Boolean.TRUE.equals(promotionSku.getHasLimit())) {
                        PromotionConstraint dbpc =
                                promotionConstraintRepository.findByCustomerAndPromotionAndProductId(customer, promotion, sku.getProduct().getProductId());
                        if (null == dbpc) {
                            throw new RuntimeException("no promotionContraint record in database");
                        }
                        Integer quantityFresh = dbpc.getQuantity() - quantity;
                        if (quantityFresh < 0) {
                            throw new RuntimeException("rollback quantity cannot be greater than quantity");
                        }
                        dbpc.setQuantity(quantityFresh);
                    }
                }
            }
            return ExtensionResultStatusType.HANDLED_STOP;
        }
    }

    /**
     * 调整变更订单库存
     * @param decrementSkuQuantities
     * @param incrementSkuQuantities
     * @param context
     * @return
     * @throws InventoryUnavailableException
     */
    @Override
    public ExtensionResultStatusType reconcileChangeOrderInventory(Map<ProductSku, Integer> decrementSkuQuantities, Map<ProductSku, Integer> incrementSkuQuantities, Map<String, Object> context) throws InventoryUnavailableException {
        return ExtensionResultStatusType.NOT_HANDLED;
    }

    @Override
    public ExtensionResultStatusType isProductBundleAvailable(Product product, int quantity, ExtensionResultHolder<Boolean> holder) {
        return ExtensionResultStatusType.NOT_HANDLED;
    }

    /**
     * 获取优先级.
     *
     * @return
     */
    @Override
    public int getPriority() {
        return 0;
    }

    /**
     * 如果为false ExtensionManager将跳过该handler
     *
     * @return
     */
    @Override
    public boolean isEnabled() {
        return true;
    }
}
